'use client';

import { useEffect, useState, useCallback, useRef } from 'react';
import { Direction, Difficulty, GameState, Position } from '../types/game';
import { GAME_SETTINGS, DIFFICULTY_SETTINGS } from '../config/gameConfig';
import { generateFood, getNextPosition, checkCollision, checkSelfCollision, calculateSpeed, isValidDirection, getInitialSnakePosition } from '../utils/gameUtils';
import GameCanvas from './GameCanvas';
import GameControls from './GameControls';
import GameStatus from './GameStatus';

export default function Game() {
  const [gameState, setGameState] = useState<GameState>({
    snake: [],
    food: null,
    direction: Direction.RIGHT,
    score: 0,
    isPlaying: false,
    gameOver: false,
    difficulty: Difficulty.MEDIUM,
    combo: 0,
    isInvincible: false,
    invincibilityTime: 0,
    highScore: 0,
    wallHitsLeft: DIFFICULTY_SETTINGS[Difficulty.MEDIUM].wallHits,
    invincibleHitsCount: 0,
    scoreToNextInvincible: 20
  });

  const [shake, setShake] = useState(false);
  const gameLoopRef = useRef<NodeJS.Timeout | null>(null);
  const lastKeyPressTimeRef = useRef<number>(0);
  const comboTimeoutRef = useRef<NodeJS.Timeout | null>(null);

  const resetGame = useCallback(() => {
    const initialSnake = getInitialSnakePosition();
    setGameState(prev => ({
      ...prev,
      snake: initialSnake,
      food: generateFood(initialSnake, 0),
      direction: Direction.RIGHT,
      score: 0,
      isPlaying: false,
      gameOver: false,
      combo: 0,
      isInvincible: false,
      invincibilityTime: 0,
      wallHitsLeft: DIFFICULTY_SETTINGS[prev.difficulty].wallHits,
      invincibleHitsCount: 0,
      scoreToNextInvincible: 20
    }));
    setShake(false);
  }, []);

  const handleKeyPress = useCallback((event: KeyboardEvent) => {
    const now = Date.now();
    if (now - lastKeyPressTimeRef.current < 50) return;
    lastKeyPressTimeRef.current = now;

    const keyDirections: { [key: string]: Direction } = {
      'ArrowUp': Direction.UP,
      'ArrowDown': Direction.DOWN,
      'ArrowLeft': Direction.LEFT,
      'ArrowRight': Direction.RIGHT,
      'w': Direction.UP,
      's': Direction.DOWN,
      'a': Direction.LEFT,
      'd': Direction.RIGHT,
      'W': Direction.UP,
      'S': Direction.DOWN,
      'A': Direction.LEFT,
      'D': Direction.RIGHT
    };

    // 如果游戏未开始且未结束，按任意方向键开始游戏
    if (!gameState.isPlaying && !gameState.gameOver && keyDirections[event.key]) {
      setGameState(prev => ({ ...prev, isPlaying: true }));
    }

    const newDirection = keyDirections[event.key];
    if (newDirection && isValidDirection(gameState.direction, newDirection)) {
      setGameState(prev => ({ ...prev, direction: newDirection }));
    }
  }, [gameState.direction, gameState.isPlaying, gameState.gameOver]);

  const updateGame = useCallback(() => {
    setGameState(prev => {
      if (!prev.isPlaying || prev.gameOver) return prev;

      const nextPosition = getNextPosition(prev.snake[0], prev.direction);
      const hasCollision = checkCollision(nextPosition);
      const hasSelfCollision = checkSelfCollision(nextPosition, prev.snake);

      // 处理撞墙逻辑
      if (hasCollision || (hasSelfCollision && prev.isInvincible)) {
        if (prev.isInvincible) {
          // 无敌状态下的碰撞处理
          const newHitsCount = prev.invincibleHitsCount + 1;
          const wrappedPosition = {
            x: ((nextPosition.x % GAME_SETTINGS.GRID_SIZE) + GAME_SETTINGS.GRID_SIZE) % GAME_SETTINGS.GRID_SIZE,
            y: ((nextPosition.y % GAME_SETTINGS.GRID_SIZE) + GAME_SETTINGS.GRID_SIZE) % GAME_SETTINGS.GRID_SIZE
          };

          // 如果达到10次碰撞，退出无敌状态
          if (newHitsCount >= 10) {
            return {
              ...prev,
              isInvincible: false,
              invincibleHitsCount: 0,
              snake: [wrappedPosition, ...prev.snake.slice(0, -1)],
            };
          }

          return {
            ...prev,
            invincibleHitsCount: newHitsCount,
            snake: [wrappedPosition, ...prev.snake.slice(0, -1)],
          };
        } else if (prev.wallHitsLeft > 0 && hasCollision) {
          // 非无敌状态下的撞墙处理
          const wrappedPosition = {
            x: ((nextPosition.x % GAME_SETTINGS.GRID_SIZE) + GAME_SETTINGS.GRID_SIZE) % GAME_SETTINGS.GRID_SIZE,
            y: ((nextPosition.y % GAME_SETTINGS.GRID_SIZE) + GAME_SETTINGS.GRID_SIZE) % GAME_SETTINGS.GRID_SIZE
          };
          setShake(true);
          return {
            ...prev,
            wallHitsLeft: prev.wallHitsLeft - 1,
            snake: [wrappedPosition, ...prev.snake.slice(0, -1)],
          };
        } else {
          setShake(true);
          return { ...prev, gameOver: true, isPlaying: false, highScore: Math.max(prev.score, prev.highScore) };
        }
      }

      const newSnake = [nextPosition, ...prev.snake];
      let newFood = prev.food;
      let newScore = prev.score;
      let newCombo = prev.combo;
      let isInvincible = prev.isInvincible;
      let scoreToNextInvincible = prev.scoreToNextInvincible;
      let invincibleHitsCount = prev.invincibleHitsCount;

      // 食物碰撞检测
      if (prev.food && nextPosition.x === prev.food.x && nextPosition.y === prev.food.y) {
        newCombo++;
        const comboBonus = Math.min(newCombo, 5);
        newScore += prev.food.points * comboBonus;
        newFood = generateFood(newSnake, newScore);

        // 在困难模式下，每累计20分进入无敌状态
        if (prev.difficulty === Difficulty.HARD && !isInvincible && newScore >= scoreToNextInvincible) {
          isInvincible = true;
          invincibleHitsCount = 0;
          scoreToNextInvincible = newScore + 20; // 设置下一个无敌状态的分数门槛
        }

        if (comboTimeoutRef.current) {
          clearTimeout(comboTimeoutRef.current);
        }
        comboTimeoutRef.current = setTimeout(() => {
          setGameState(prev => ({ ...prev, combo: 0 }));
        }, GAME_SETTINGS.COMBO_TIMEOUT);
      } else {
        newSnake.pop();
      }

      return {
        ...prev,
        snake: newSnake,
        food: newFood,
        score: newScore,
        combo: newCombo,
        isInvincible,
        invincibilityTime: isInvincible ? prev.invincibilityTime : 0,
        wallHitsLeft: prev.wallHitsLeft,
        invincibleHitsCount,
        scoreToNextInvincible
      };
    });
  }, []);

  useEffect(() => {
    if (shake) {
      setTimeout(() => setShake(false), 300);
    }
  }, [shake]);

  useEffect(() => {
    window.addEventListener('keydown', handleKeyPress);
    return () => window.removeEventListener('keydown', handleKeyPress);
  }, [handleKeyPress]);

  useEffect(() => {
    if (gameState.isPlaying && !gameState.gameOver) {
      const speed = calculateSpeed(gameState.score, DIFFICULTY_SETTINGS[gameState.difficulty]);
      gameLoopRef.current = setInterval(updateGame, speed);
      return () => {
        if (gameLoopRef.current) clearInterval(gameLoopRef.current);
      };
    }
  }, [gameState.isPlaying, gameState.gameOver, gameState.score, gameState.difficulty, updateGame]);

  useEffect(() => {
    resetGame();
  }, [resetGame]);

  const handleStart = () => {
    if (!gameState.isPlaying && !gameState.gameOver) {
      setGameState(prev => ({ ...prev, isPlaying: true }));
    }
  };

  const handlePause = () => {
    setGameState(prev => ({ ...prev, isPlaying: false }));
  };

  const handleRestart = () => {
    resetGame();
  };

  const handleDifficultyChange = (difficulty: Difficulty) => {
    const initialSnake = getInitialSnakePosition();
    setGameState(prev => ({
      ...prev,
      difficulty,
      snake: initialSnake,
      food: generateFood(initialSnake, 0),
      direction: Direction.RIGHT,
      score: 0,
      isPlaying: false,
      gameOver: false,
      combo: 0,
      isInvincible: false,
      invincibilityTime: 0,
      wallHitsLeft: DIFFICULTY_SETTINGS[difficulty].wallHits,
      invincibleHitsCount: 0,
      scoreToNextInvincible: 20
    }));
    setShake(false);
  };

  return (
    <div className="flex flex-col items-center justify-center min-h-screen bg-gray-100 py-8">
      <h1 className="text-4xl font-bold mb-8">贪吃蛇游戏</h1>
      <GameCanvas gameState={gameState} shake={shake} />
      <GameStatus
        score={gameState.score}
        combo={gameState.combo}
        difficulty={gameState.difficulty}
        isInvincible={gameState.isInvincible}
        invincibilityTime={gameState.invincibilityTime}
        highScore={gameState.highScore}
        invincibleHitsCount={gameState.invincibleHitsCount}
        scoreToNextInvincible={gameState.scoreToNextInvincible}
      />
      <GameControls
        isPlaying={gameState.isPlaying}
        gameOver={gameState.gameOver}
        difficulty={gameState.difficulty}
        onStart={handleStart}
        onPause={handlePause}
        onRestart={handleRestart}
        onDifficultyChange={handleDifficultyChange}
      />
    </div>
  );
} 